#ifndef __MINIUTIL_FRAME_SRPC_H__
#define __MINIUTIL_FRAME_SRPC_H__

#include <string>
#include <vector>
#include "miniutil/ref_ptr.h"
#include "miniutil/address.h"
#include "miniutil/threadservice.h"
#include "miniutil/socketmultiplex.h"
#include "miniutil/multinetservice.h"
#include "miniutil/lenmsgreader.h"

namespace miniutil { namespace frame {

    class ParaBasic
    {
        public:
            const static int PARA_UNKNOW = -1;
            const static int PARA_CHAR = 0;
            const static int PARA_SHORT = 1;
            const static int PARA_INT32 = 2;
            const static int PARA_INT64 = 3;
            const static int PARA_STRING = 4;
            const static int PARA_BUFFER = 5;
        public:
			virtual ~ParaBasic(){}
            virtual int getType() = 0;
			virtual operator std::string() = 0;
    };
    
    template <class TN>
    class ParaTraits
    {
        public:
            const static int type = ParaBasic::PARA_UNKNOW;
    };
    
    template<> class ParaTraits<char>
    {
        public:
            const static int type = ParaBasic::PARA_CHAR;
    };

    template<> class ParaTraits<unsigned char>
    {
        public:
            const static int type = ParaBasic::PARA_CHAR;
    };    
  
    template<> class ParaTraits<short>
    {
        public:
            const static int type = ParaBasic::PARA_SHORT;
    };    
 
    template<> class ParaTraits<unsigned short>
    {
        public:
            const static int type = ParaBasic::PARA_SHORT;
    };    
 
    template<> class ParaTraits<int>
    {
        public:
            const static int type = ParaBasic::PARA_INT32;
    };    
 
    template<> class ParaTraits<unsigned int>
    {
        public:
            const static int type = ParaBasic::PARA_INT32;
    };    
 
   template<> class ParaTraits<long long>
    {
        public:
            const static int type = ParaBasic::PARA_INT64;
    };    
 
   template<> class ParaTraits<unsigned long long>
    {
        public:
            const static int type = ParaBasic::PARA_INT64;
    };    
 
   template<> class ParaTraits<std::string>
    {
        public:
            const static int type = ParaBasic::PARA_STRING;
    };    
    
    template<> class ParaTraits<char*>
    {
        public:
            const static int type = ParaBasic::PARA_BUFFER;
    };     
 
   template<class TN>
    class RpcCallPara:public ParaBasic
    {
        public:
            RpcCallPara(TN vle)
                :mvalue(vle)
            {
            }
                
            virtual int getType()
            {
                return ParaTraits<TN>::type;
            }

			virtual operator std::string()
			{
				std::stringstream str;
				str<<mvalue;
				return str.str();
			}

         public:
            TN mvalue;
    };
    
    template<>
    class RpcCallPara<char*>:public ParaBasic
    {
        public:
            RpcCallPara(char* v, int len)
            {
                mpvalue = v;
                mlen = len;
            }
            
            virtual int getType()
            {
				return ParaBasic::PARA_BUFFER;
            }

			virtual operator std::string()
			{
				std::string rtn(mpvalue, mlen);
				return rtn;
			}
	
		public:
            char* mpvalue;
            int mlen;
    };

//---------------------------------------------------------------------------------
    class RpcMessage
    {
    public:
        static const short REQU = 0;
        static const short RESP = 1;
        static int ssessid;;
    public:
        static int getSessionid();
        ~RpcMessage();
        
        RpcMessage(std::string func)
		{
			mfunction = func;
			mmsgtype = REQU;
			RpcCallPara<std::string> *ps = new RpcCallPara<std::string>(func);
			mvparas.push_back(ps);
		}

    
        template <class T1> 
        RpcMessage(std::string func, T1 para1)
		{
			mfunction = func;
			RpcCallPara<std::string> *ps = new RpcCallPara<std::string>(func);
			mvparas.push_back(ps);
			RpcCallPara<T1> *pt1 = new RpcCallPara<T1>(para1);
			mvparas.push_back(pt1);
			mmsgtype = REQU;
		}

        template <class T1, class T2>
        RpcMessage(std::string func, T1 para1, T2 para2)
		{
			mfunction = func;
			RpcCallPara<std::string> *ps = new RpcCallPara<std::string>(func);
			mvparas.push_back(ps);
			RpcCallPara<T1> *pt1 = new RpcCallPara<T1>(para1);
			mvparas.push_back(pt1);
			RpcCallPara<T2> *pt2 = new RpcCallPara<T2>(para2);
			mvparas.push_back(pt2);
			mmsgtype = REQU;
		}

        template <class T1, class T2, class T3>
        RpcMessage(std::string func, T1 para1, T2 para2, T3 para3)
		{
			mfunction = func;
			RpcCallPara<std::string> *ps = new RpcCallPara<std::string>(func);
			mvparas.push_back(ps);
			RpcCallPara<T1> *pt1 = new RpcCallPara<T1>(para1);
			mvparas.push_back(pt1);
			RpcCallPara<T2> *pt2 = new RpcCallPara<T2>(para2);
			mvparas.push_back(pt2);
			RpcCallPara<T3> *pt3 = new RpcCallPara<T1>(para3);
			mvparas.push_back(pt3);
			mmsgtype = REQU;
		}

        template <class T1, class T2, class T3, class T4>
        RpcMessage(std::string func, T1 para1, T2 para2, T3 para3, T4 para4)
		{
			mfunction = func;
			RpcCallPara<std::string> *ps = new RpcCallPara<std::string>(func);
			mvparas.push_back(ps);
			RpcCallPara<T1> *pt1 = new RpcCallPara<T1>(para1);
			mvparas.push_back(pt1);
			RpcCallPara<T2> *pt2 = new RpcCallPara<T2>(para2);
			mvparas.push_back(pt2);
			RpcCallPara<T3> *pt3 = new RpcCallPara<T3>(para3);
			mvparas.push_back(pt3);
			RpcCallPara<T4> *pt4 = new RpcCallPara<T4>(para4);
			mvparas.push_back(pt4);
			mmsgtype = REQU;
		}
        
		RpcMessage(const std::vector<std::string> &paras);
        //RpcMessage(std::string&, std::vector< ParaBasic*>& vparas);
        
        RpcMessage(int len, const char* pbuf);
       
        int getCreateMsgLen();
        int toBuffer(char*, int len);
        int fromBuffer(const char*, int);
    
        int mmsgtype;
        std::string mfunction;
        int msessid;
        std::string mformat;
        std::vector< ParaBasic*> mvparas;
    private:
        std::pair<std::string, int> getMsgStus(const std::vector< ParaBasic*>& vparas);
        RpcMessage & operator = (const RpcMessage &){}
        RpcMessage(const RpcMessage&){}
   };
    
    
    typedef miniutil::data::ref_ptr<RpcMessage> ShareRpcMsg;
    typedef std::vector< ParaBasic*> RpcResp;

	class RpcNode:public MultinetPeer
    {
        public:
            const static int SYNC = 1;  //invoke function will wait for response
            const static int WAITRESP = 2;   //asyn opreation want response, or it will be dropped!
            
        public:
			RpcNode(miniutil::multinet::SocketMulplexService* pmul, miniutil::soaddr raddr);
			RpcNode(miniutil::multinet::SocketMulplexService* pmul, miniutil::soaddr raddr, SOCKET);

            //int invoke(std::string);
            //int invoke(std::stirng, RpcResp &);

            //the number of parameter must not same, should not use default value parameter!!!
         //   int invoke(std::string, int falg = SYNC);
	        //template <class T1> 
	        //int invoke(std::string, T1 para1, int falg = SYNC);
	        //template <class T1, class T2>
	        //int invoke(std::string, T1 para1, T2 para2, int falg = SYNC);
	        //template <class T1, class T2, class T3>
	        //int invoke(std::string, T1 para1, T2 para2, T3 para3, int falg = SYNC);
	        //template <class T1, class T2, class T3, class T4>
	        //int invoke(std::string, T1 para1, T2 para2, T3 para3, T4 para4, int falg = SYNC);
            	
            int invoke(ShareRpcMsg smsg, int flag);
            //int invoke(std::string, std::vector< ParaBasic*> vparas, int flag = SYNC);
            
            //int getRemoteRpcResp(int sessid, ShareRpcMsg& msg);
            //int getRemoteRpcReq(std::vector< ShareRpcMsg>& vmsgs);

            virtual int working();
        public:
            //int analyze(char* pbuf, int len);

            miniutil::multinet::LenMsgReader mmsgreader;
            //std::set<int> mwaitingsession;
            std::map<int, ShareRpcMsg> mvremoterespmsgs;
            std::vector<ShareRpcMsg> mvremotereqmsgs;            
    };
    
    class RpcNodeHandler
    {
        public:
            virtual int operator()(RpcNode*) = 0;
    };
    
    class RpcService:public MultinetService<RpcNode>
    {
        public:
			RpcService(unsigned short port);
            void broadcast(ShareRpcMsg);
            void checkNode(RpcNodeHandler* phandler);
    };
} }

#endif
